#include "stdafx.h"
#include "KeyHandler.h"
#include "CompAndCandWnd.h"
#include "ImmStuff.h"
#include "KnowledgeBase.h"

UINT KeyHandler::GetKeyType(BYTE key)
{
	if(key >= VK_0 && key <= VK_9)
		return 1;
	else if(key >= VK_A && key <= VK_Z)
		return 2;
	else if(key == VK_SPACE)
		return 3;
	else if(key == VK_RETURN)
		return 4;
	else if(key == VK_BACK)
		return 5;
	else if(key == VK_ESCAPE)
		return 6;
	else if(key == VK_SHIFT)
		return 7;
	else if(key == VK_MINUS || key == VK_EQUAL || key == VK_COMMA || key == VK_DOT)
		return 8;
	else
		return 0;
}
BYTE KeyHandler::CurrentKey = 0;
BOOL KeyHandler::DirectCodeInput = FALSE;

KeyHandler::KeyHandler(HIMC hIMC,UINT uVKey,LPDWORD lpdwTransKey,UINT lparam,CONST LPBYTE lpbKState) : lpKeyState(lpbKState),vKey(uVKey),lparam(lparam)
{
	this->lpImmData = new ImmData(hIMC);
	this->lpTransKey = lpdwTransKey;
	CurrentKey = uVKey;
}

BOOL KeyHandler::_keyShiftSinglePress()
{
	static BOOL flag = FALSE;
	if(this->vKey == VK_SHIFT)
	{
		if(this->lparam & 0x80000000)
		{
			return flag;
		}
		else
		{
			flag = TRUE;
		}
	}
	else
		flag = FALSE;
	return FALSE;
}

KeyHandler::~KeyHandler()
{
	if(this->lpImmData)
		delete this->lpImmData;
}

VOID KeyHandler::HandleEx()
{
	if(this->lparam & 0x8000)
		this->_handlExKeyUp();
	else
	{
		UINT keyType = GetKeyType(this->vKey);
		if(!keyType)
		{
			MessageBeep(0xFFFFFFFF);
			return;
		}
		if(keyType == 3)
		{
			if(KnowledgeProcess(this->lpImmData).SelectTheFirst(DirectCodeInput))
				this->lpImmData->MakeResultString(this->lpTransKey,TRUE);
			else
				MessageBeep(0xFFFFFFFF);
		}
		else if (keyType == 6)
			this->lpImmData->MakeResultString(this->lpTransKey,FALSE);
		else if(keyType == 4)
			this->lpImmData->OutputCompString(this->lpTransKey);
		else
		{
			if(DirectCodeInput)
				this->_directCodeInputProcess();
			else
				this->_handlExKeyDown();
		}
	}
}
VOID KeyHandler::_directCodeInputProcess()
{
	this->lpImmData->WM_StartComp(this->lpTransKey);
	CompositionStringClass* lpCompStrClass = this->lpImmData->GetCompStrClass();
	BOOL shiftKeyPress = FALSE;
	UINT keyType = GetKeyType(this->vKey);
	if(this->lpKeyState[VK_SHIFT] & 0x80 && this->vKey != VK_SHIFT)
	{
		shiftKeyPress = TRUE;
	}
	if(lpCompStrClass->GetInputLen() == 0)//the first input.
	{
		if(keyType == 2) // the first input char must range in a-z 
		{
			TCHAR str[2];
			str[0] = (TCHAR)(this->vKey );
			str[1] = '\0';
			lpCompStrClass->PutCode(str);
		}
		else
		{
			MessageBeep(0xFFFFFFFF);
			return;
		}
	}
	else
	{
		if(shiftKeyPress) // shift key is pressed.
		{
			if(keyType == 2)
			{
				USRINPUT ipt = lpCompStrClass->GetInput(lpCompStrClass->GetInputLen() - 1);
				if(_tcslen(ipt.baseCode) == 1 && ipt.baseCode[0] - 32 >= VK_A && ipt.baseCode[0] - 32 <= VK_Z)
				{
					MessageBeep(0xFFFFFFFF);
					return;
				}
				else
				{					
					TCHAR str[2];
					str[0] = (TCHAR)(this->vKey );
					str[1] = '\0';
					lpCompStrClass->PutCode(str);
				}
			}
			else // shift with other combination is invalid.
			{
				MessageBeep(0xFFFFFFFF);
				return;
			}
		}
		else
		{
			if(keyType == 1 || keyType == 2)
			{
				USRINPUT ipt = lpCompStrClass->GetInput(lpCompStrClass->GetInputLen() - 1);
				if(_tcslen(ipt.baseCode) == 1)
				{
					if(ipt.baseCode[0] >= VK_A && ipt.baseCode[0] <= VK_Z)
					{
						TCHAR str[2];
						if(keyType == 2)
							str[0] = (TCHAR)(this->vKey + 32);
						else
							str[0] = (TCHAR)(this->vKey);
						str[1] = '\0';
						lpCompStrClass->PutCode(str);
					}
					else
					{
						if(keyType == 2)
							ipt.baseCode[1] = (TCHAR)(this->vKey + 32);
						else
							ipt.baseCode[1] = (TCHAR)(this->vKey);
						ipt.baseCode[2] = '\0';
						lpCompStrClass->UndoInput();
						lpCompStrClass->PutCode(ipt.baseCode);
					}
				}
				else
				{
					TCHAR str[2];
					if(keyType == 2)
						str[0] = (TCHAR)(this->vKey + 32);
					else
						str[0] = (TCHAR)(this->vKey);
					str[1] = '\0';
					lpCompStrClass->PutCode(str);
				}
			}
			else if(keyType == 5)
			{
				lpCompStrClass->UndoInput();
				if(lpCompStrClass->GetInputLen() == 0)
				{
					this->lpImmData->WM_CompStr(this->lpTransKey);
					return;
				}
			}
			else
			{
				MessageBeep(0xFFFFFFFF);
				return;
			}
		}
	}
	this->lpImmData->WM_CompStr(this->lpTransKey);
	this->lpImmData->GetCandStrClass()->ClearCandidateStr();
}

VOID KeyHandler::_handlExKeyDown()
{
	this->lpImmData->WM_StartComp(this->lpTransKey);
	CompositionStringClass* lpCompStrClass = this->lpImmData->GetCompStrClass();
	BOOL shiftKeyPress = FALSE;
	UINT keyType = GetKeyType(this->vKey);
	if(this->lpKeyState[VK_SHIFT] & 0x80 && this->vKey != VK_SHIFT)
	{
		shiftKeyPress = TRUE;
	}
	if(lpCompStrClass->GetInputLen() == 0)//the first input.
	{
		if(keyType == 2) // the first input char must range in a-z 
		{
			TCHAR str[2];
			str[0] = (TCHAR)(this->vKey );
			str[1] = '\0';
			lpCompStrClass->PutCode(str);
		}
		else
		{
			MessageBeep(0xFFFFFFFF);
			return;
		}
	}
	else
	{
		if(shiftKeyPress) // shift key is pressed.
		{
			if(keyType == 1) // number key. indicate that user select a stroke.
			{
				lpCompStrClass->PutStroke(this->vKey - VK_0);
			}
			else if(keyType == 2) // char key. indicate that user select a pinyin.
			{
				lpCompStrClass->PutPY((TCHAR)(this->vKey));
			}
			else // shift with other combination is invalid.
			{
				MessageBeep(0xFFFFFFFF);
				return;
			}
		}
		else
		{
			if(keyType == 1)
			{
				BYTE selectIndex = this->vKey;
				selectIndex -= VK_0;
				if(selectIndex == 0) 
					selectIndex = 10;
				selectIndex -= 1;
				LPCANDSTRUCT p = this->lpImmData->GetCandStrClass()->GetCode(selectIndex);
				if(p)
				{
					if(p->isCompleteWord)
					{
						this->lpImmData->GetCompStrClass()->SetResultString(p->szCnadStr);
						this->lpImmData->MakeResultString(this->lpTransKey,TRUE);
						return;
					}
					else
						lpCompStrClass->PutCode(p->szCnadStr);
				}
				else
				{
					MessageBeep(0xFFFFFFFF);
					return;
				}
			}
			else if(keyType == 2)
			{
				TCHAR str[2];
				str[0] = (TCHAR)(this->vKey );
				str[1] = '\0';
				lpCompStrClass->PutCode(str);
			}
			else if(keyType == 5)
			{
				lpCompStrClass->UndoInput();
				if(lpCompStrClass->GetInputLen() == 0)
				{
					this->lpImmData->WM_CompStr(this->lpTransKey);
					return;
				}
			}
			else if(keyType == 8)
			{
				if(this->vKey == VK_MINUS || this->vKey == VK_COMMA)
				{
					this->lpImmData->GetCandStrClass()->GoToPreviousPage();
				}
				else
				{
					this->lpImmData->GetCandStrClass()->GoToNextPage();
				}
			}
		}
	}
	
	if(keyType != 8)// not page changing.
	{
		UINT re = KnowledgeProcess(this->lpImmData).TranslateInput();
		if(re == 1)
		{
			this->lpImmData->MakeResultString(this->lpTransKey,TRUE);
			return;
		}
		else if(re == 0)
		{
			MessageBeep(0xFFFFFFFF);
			this->lpImmData->GetCompStrClass()->UndoInput();
		}
	}	
	this->lpImmData->WM_CompStr(this->lpTransKey);
}

VOID KeyHandler::_handlExKeyUp()
{
	//MessageBox(NULL,_T("up"),_T("Init"),MB_OK);
	//ImmStuff::WM_Comp(this->hIMC,this->lpTransKey);
}

BOOL KeyHandler::Process()
{
	if(this->_keyShiftSinglePress())
	{
		this->lpImmData->ToggleImmOpenState();
		this->lpImmData->MakeResultString(this->lpTransKey,FALSE);
		return FALSE;
	}
	if(!this->lpImmData->GetImmOpenState())
		return FALSE;

	if(this->lpImmData->GetCompStrClass()->GetInputLen() == 0)
	{
		if(vKey < VK_A || vKey > VK_Z)
		{
			if(vKey == VK_F2 && this->lparam & 0x80000000)
				DirectCodeInput = !DirectCodeInput;
			return FALSE;
		}
		else
		{
			if(this->lpKeyState[VK_CONTROL] & 0x80)
				return FALSE;
			if(this->lpKeyState[VK_MENU] & 0x80)
				return FALSE;
			//if(this->lparam & 0x200000000) // Alt key was pressed.
			//	return FALSE;
		}
	}
	if(this->lparam & 0x80000000)
		return this->_processKeyUp();
	else
		return this->_processKeyDown();
}

BOOL KeyHandler::_processKeyDown()
{
	return TRUE;
}

BOOL KeyHandler::_processKeyUp()
{
	return TRUE;
}